ui/appDisplay.js \
ui/appFavorites.js \
ui/backgroundMenu.js \
+ ui/background.js \
ui/boxpointer.js \
ui/calendar.js \
ui/checkBox.js \
--- /dev/null
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const Clutter = imports.gi.Clutter;
+const GDesktopEnums = imports.gi.GDesktopEnums;
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Lang = imports.lang;
+const Meta = imports.gi.Meta;
+const Signals = imports.signals;
+
+const Main = imports.ui.main;
+const Params = imports.misc.params;
+const Tweener = imports.ui.tweener;
+
+const BACKGROUND_SCHEMA = 'org.gnome.desktop.background';
+const DRAW_BACKGROUND_KEY = 'draw-background';
+const PRIMARY_COLOR_KEY = 'primary-color';
+const SECONDARY_COLOR_KEY = 'secondary-color';
+const COLOR_SHADING_TYPE_KEY = 'color-shading-type';
+const BACKGROUND_STYLE_KEY = 'picture-options';
+const PICTURE_OPACITY_KEY = 'picture-opacity';
+const PICTURE_URI_KEY = 'picture-uri';
+
+const FADE_ANIMATION_TIME = 1.0;
+
+let _backgroundCache = null;
+
+const BackgroundCache = new Lang.Class({
+ Name: 'BackgroundCache',
+
+ _init: function() {
+ this._patterns = [];
+ this._images = [];
+ this._fileMonitors = {};
+ },
+
+ getPatternContent: function(params) {
+ params = Params.parse(params, { monitorIndex: 0,
+ color: null,
+ secondColor: null,
+ shadingType: null,
+ effects: Meta.BackgroundEffects.NONE });
+
+ let content = null;
+ let candidateContent = null;
+ for (let i = 0; i < this._patterns.length; i++) {
+ if (!this._patterns[i])
+ continue;
+
+ if (this._patterns[i].get_shading() != params.shadingType)
+ continue;
+
+ if (!params.color.equal(this._patterns[i].get_color()))
+ continue;
+
+ if (params.shadingType != GDesktopEnums.BackgroundShading.SOLID &&
+ !params.secondColor.equal(this._patterns[i].get_second_color()))
+ continue;
+
+ candidateContent = this._patterns[i];
+
+ if (params.effects != this._patterns[i].effects)
+ continue;
+
+ break;
+ }
+
+ if (candidateContent) {
+ content = candidateContent.copy(params.monitorIndex, params.effects);
+ } else {
+ content = new Meta.Background({ meta_screen: global.screen,
+ monitor: params.monitorIndex,
+ effects: params.effects });
+
+ if (params.shadingType == GDesktopEnums.BackgroundShading.SOLID) {
+ content.load_color(params.color);
+ } else {
+ content.load_gradient(params.shadingType, params.color, params.secondColor);
+ }
+
+ this._patterns.push(content);
+ }
+
+ return content;
+ },
+
+ _monitorFile: function(filename) {
+ if (this._fileMonitors[filename])
+ return;
+
+ let file = Gio.File.new_for_path(filename);
+ let monitor = file.monitor(Gio.FileMonitorFlags.NONE, null);
+
+ let signalId = monitor.connect('changed',
+ Lang.bind(this, function() {
+ for (let i = 0; i < this._images.length; i++) {
+ if (this._images[i].get_filename() == filename)
+ this._images.splice(i, 1);
+ }
+
+ monitor.disconnect(signalId);
+
+ this.emit('file-changed', filename);
+ }));
+
+ this._fileMonitors[filename] = monitor;
+ },
+
+ _removeContent: function(contentList, content) {
+ let index = contentList.indexOf(content);
+
+ if (index >= 0)
+ contentList.splice(index, 1);
+ },
+
+ removePatternContent: function(content) {
+ this._removeContent(this._patterns, content);
+ },
+
+ removeImageContent: function(content) {
+ this._removeContent(this._images, content);
+ },
+
+ getImageContent: function(params) {
+ params = Params.parse(params, { monitorIndex: 0,
+ style: null,
+ filename: null,
+ effects: Meta.BackgroundEffects.NONE,
+ cancellable: null,
+ onFinished: null });
+
+ let content = null;
+ let candidateContent = null;
+ for (let i = 0; i < this._images.length; i++) {
+ if (!this._images[i])
+ continue;
+
+ if (this._images[i].get_style() != params.style)
+ continue;
+
+ if (this._images[i].get_filename() != params.filename)
+ continue;
+
+ if (params.style == GDesktopEnums.BackgroundStyle.SPANNED &&
+ this._images[i].monitor_index != this._monitorIndex)
+ continue;
+
+ candidateContent = this._images[i];
+
+ if (params.effects != this._images[i].effects)
+ continue;
+
+ break;
+ }
+
+ if (candidateContent) {
+ content = candidateContent.copy(params.monitorIndex, params.effects);
+
+ if (params.onFinished)
+ params.onFinished(content);
+ } else {
+ content = new Meta.Background({ meta_screen: global.screen,
+ monitor: params.monitorIndex,
+ effects: params.effects });
+
+ content.load_file_async(params.filename,
+ params.style,
+ params.cancellable,
+ Lang.bind(this,
+ function(object, result) {
+ try {
+ content.load_file_finish(result);
+
+ this._monitorFile(params.filename);
+ this._images.push(content);
+ } catch(e) {
+ content = null;
+ }
+
+ if (params.onFinished)
+ params.onFinished(content);
+ }));
+ }
+ }
+});
+Signals.addSignalMethods(BackgroundCache.prototype);
+
+function getBackgroundCache() {
+ if (!_backgroundCache)
+ _backgroundCache = new BackgroundCache();
+ return _backgroundCache;
+}
+
+const Background = new Lang.Class({
+ Name: 'Background',
+
+ _init: function(params) {
+ params = Params.parse(params, { monitorIndex: 0,
+ effects: Meta.BackgroundEffects.NONE });
+ this.actor = new Meta.BackgroundGroup();
+ this.actor._delegate = this;
+
+ this._destroySignalId = this.actor.connect('destroy',
+ Lang.bind(this, this._destroy));
+
+ this._settings = new Gio.Settings({ schema: BACKGROUND_SCHEMA });
+ this._monitorIndex = params.monitorIndex;
+ this._effects = params.effects;
+ this._fileWatches = {};
+ this._pattern = null;
+ this._image = null;
+
+ this._brightness = 1.0;
+ this._vignetteSharpness = 0.2;
+ this._saturation = 1.0;
+ this._cancellable = new Gio.Cancellable();
+ this.isLoaded = false;
+
+ this._settings.connect('changed', Lang.bind(this, function() {
+ this.emit('changed');
+ }));
+
+ this._load();
+ },
+
+ _destroy: function() {
+ this._cancellable.cancel();
+ this._cancellable = null;
+
+ let i;
+
+ let keys = Object.keys(this._fileWatches);
+ for (i = 0; i < keys.length; i++) {
+ this._cache.disconnect(this._fileWatches[keys[i]]);
+ }
+ this._fileWatches = null;
+
+ if (this._pattern) {
+ if (this._pattern.content)
+ this._cache.removePatternContent(this._pattern.content);
+
+ this._pattern.destroy();
+ this._pattern = null;
+ }
+
+ if (this._image) {
+ if (this._image.content)
+ this._cache.removeImageContent(this._image.content);
+
+ this._image.destroy();
+ this._image = null;
+ }
+
+ this.actor.disconnect(this._destroySignalId);
+ this._destroySignalId = 0;
+ this.actor.destroy();
+ },
+
+ _setLoaded: function() {
+ if (this.isLoaded)
+ return;
+
+ this.isLoaded = true;
+
+ GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
+ this.emit('loaded');
+ return false;
+ }));
+ },
+
+ _loadPattern: function() {
+ let colorString, res, color, secondColor;
+
+ colorString = this._settings.get_string(PRIMARY_COLOR_KEY);
+ [res, color] = Clutter.Color.from_string(colorString);
+ colorString = this._settings.get_string(SECONDARY_COLOR_KEY);
+ [res, secondColor] = Clutter.Color.from_string(colorString);
+
+ let shadingType = this._settings.get_enum(COLOR_SHADING_TYPE_KEY);
+
+ let content = this._cache.getPatternContent({ monitorIndex: this._monitorIndex,
+ effects: this._effects,
+ color: color,
+ secondColor: secondColor,
+ shadingType: shadingType });
+
+ this._pattern = new Meta.BackgroundActor();
+ this.actor.add_child(this._pattern);
+
+ this._pattern.content = content;
+ },
+
+ _watchCacheFile: function(filename) {
+ if (this._fileWatches[filename])
+ return;
+
+ let signalId = this._cache.connect('file-changed',
+ Lang.bind(this, function(cache, changedFile) {
+ if (changedFile == filename) {
+ this.emit('changed');
+ }
+ }));
+ this._fileWatches[filename] = signalId;
+ },
+
+ _setImage: function(content, filename) {
+ content.saturation = this._saturation;
+ content.brightness = this._brightness;
+ content.vignette_sharpness = this._vignetteSharpness;
+
+ this._image = new Meta.BackgroundActor();
+ this._image.content = content;
+ this.actor.add_child(this._image);
+ this._watchCacheFile(filename);
+ },
+
+ _loadFile: function(filename) {
+ this._cache.getImageContent({ monitorIndex: this._monitorIndex,
+ effects: this._effects,
+ style: this._style,
+ filename: filename,
+ cancellable: this._cancellable,
+ onFinished: Lang.bind(this, function(content) {
+ if (!content) {
+ return;
+ }
+
+ this._setImage(content, filename);
+ this._setLoaded();
+ })
+ });
+
+ },
+
+ _load: function () {
+ if (!this._settings.get_boolean(DRAW_BACKGROUND_KEY)) {
+ this._setLoaded();
+ return;
+ }
+
+ this._cache = getBackgroundCache();
+
+ this._loadPattern(this._cache);
+
+ this._style = this._settings.get_enum(BACKGROUND_STYLE_KEY);
+ if (this._style == GDesktopEnums.BackgroundStyle.NONE) {
+ this._setLoaded();
+ return;
+ }
+
+ let uri = this._settings.get_string(PICTURE_URI_KEY);
+ let filename = Gio.File.new_for_uri(uri).get_path();
+
+ this._loadFile(filename);
+ },
+
+ get saturation() {
+ return this._saturation;
+ },
+
+ set saturation(saturation) {
+ this._saturation = saturation;
+
+ if (this._pattern && this._pattern.content)
+ this._pattern.content.saturation = saturation;
+
+ if (this._image && this._image.content)
+ this._image.content.saturation = saturation;
+ },
+
+ get brightness() {
+ return this._brightness;
+ },
+
+ set brightness(factor) {
+ this._brightness = factor;
+ if (this._pattern && this._pattern.content)
+ this._pattern.content.brightness = factor;
+
+ if (this._image && this._image.content)
+ this._image.content.brightness = factor;
+ },
+
+ get vignetteSharpness() {
+ return this._vignetteSharpness;
+ },
+
+ set vignetteSharpness(sharpness) {
+ this._vignetteSharpness = sharpness;
+ if (this._pattern && this._pattern.content)
+ this._pattern.content.vignette_sharpness = sharpness;
+
+ if (this._image && this._image.content)
+ this._image.content.vignette_sharpness = sharpness;
+ }
+});
+Signals.addSignalMethods(Background.prototype);
+
+const StillFrame = new Lang.Class({
+ Name: 'StillFrame',
+
+ _init: function(monitorIndex) {
+ this.actor = new Meta.BackgroundActor();
+ this.actor._delegate = this;
+
+ let content = new Meta.Background({ meta_screen: global.screen,
+ monitor: monitorIndex,
+ effects: Meta.BackgroundEffects.NONE });
+ content.load_still_frame();
+
+ this.actor.content = content;
+ }
+});
+Signals.addSignalMethods(StillFrame.prototype);
+
+const BackgroundManager = new Lang.Class({
+ Name: 'BackgroundManager',
+
+ _init: function(params) {
+ params = Params.parse(params, { container: null,
+ layoutManager: Main.layoutManager,
+ monitorIndex: null,
+ effects: Meta.BackgroundEffects.NONE });
+
+ this._container = params.container;
+ this._layoutManager = params.layoutManager;
+ this._effects = params.effects;
+ this._monitorIndex = params.monitorIndex;
+
+ this.background = this._createBackground();
+ this._newBackground = null;
+ this._loadedSignalId = 0;
+ this._changedSignalId = 0;
+ },
+
+ destroy: function() {
+ if (this._loadedSignalId)
+ this._newBackground.disconnect(this._loadedSignalId);
+
+ if (this._changedSignalId)
+ this.background.disconnect(this._changedSignalId);
+
+ if (this._newBackground) {
+ let container = this._newBackground.actor.get_parent();
+ if (container)
+ container.remove_actor(this._newBackground.actor);
+ this._newBackground = null;
+ }
+
+ if (this.background) {
+ let container = this.background.actor.get_parent();
+ if (container)
+ container.remove_actor(this.background.actor);
+ this.background = null;
+ }
+ },
+
+ _updateBackground: function(background, monitorIndex) {
+ let newBackground = this._createBackground(monitorIndex);
+ newBackground.vignetteSharpness = background.vignetteSharpness;
+ newBackground.brightness = background.brightness;
+ newBackground.saturation = background.saturation;
+ newBackground.visible = background.visible;
+
+ let signalId = newBackground.connect('loaded',
+ Lang.bind(this, function() {
+ newBackground.disconnect(signalId);
+ Tweener.addTween(background.actor,
+ { opacity: 0,
+ time: FADE_ANIMATION_TIME,
+ transition: 'easeOutQuad',
+ onComplete: Lang.bind(this, function() {
+ this.background = newBackground;
+ this._newBackground = null;
+ this._container.remove_actor(background.actor);
+ this.emit('changed');
+ })
+ });
+ }));
+ this._loadedSignalId = signalId;
+
+ this._newBackground = newBackground;
+ },
+
+ _createBackground: function() {
+ let background = new Background({ monitorIndex: this._monitorIndex,
+ layoutManager: this._layoutManager,
+ effects: this._effects });
+ this._container.add_child(background.actor);
+
+ let monitor = this._layoutManager.monitors[this._monitorIndex];
+ background.actor.set_position(monitor.x, monitor.y);
+ background.actor.set_size(monitor.width, monitor.height);
+ background.actor.lower_bottom();
+
+ let signalId = background.connect('changed', Lang.bind(this, function() {
+ background.disconnect(signalId);
+ this._updateBackground(background, this._monitorIndex);
+ }));
+
+ this._changedSignalId = signalId;
+
+ return background;
+ },
+});
+Signals.addSignalMethods(BackgroundManager.prototype);
const Signals = imports.signals;
const St = imports.gi.St;
+const Background = imports.ui.background;
+const BackgroundMenu = imports.ui.backgroundMenu;
+
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
-const STARTUP_ANIMATION_TIME = 0.2;
+const STARTUP_ANIMATION_TIME = 0.5;
const KEYBOARD_ANIMATION_TIME = 0.15;
-const PLYMOUTH_TRANSITION_TIME = 1;
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
// The message tray takes this much pressure
this.primaryIndex = -1;
this._keyboardIndex = -1;
this._hotCorners = [];
- this._background = null;
this._leftPanelBarrier = null;
this._rightPanelBarrier = null;
this._trayBarrier = null;
global.stage.remove_actor(global.top_window_group);
this.uiGroup.add_actor(global.top_window_group);
+ this._consoleBackgroundGroup = new Meta.BackgroundGroup();
+ global.stage.insert_child_below(this._consoleBackgroundGroup, null);
+
+ this._backgroundGroup = new Meta.BackgroundGroup();
+ global.window_group.add_child(this._backgroundGroup);
+ this._backgroundGroup.lower_bottom();
+ this._bgManagers = [];
+
// This blocks the XDND picks from finding the activities button
// and we never attempt to pick anything from it anyway so make
// it invisible from picks
global.screen.connect('monitors-changed',
Lang.bind(this, this._monitorsChanged));
this._monitorsChanged();
+ this._prepareStartupAnimation();
},
// This is called by Main after everything else is constructed;
}
},
+ _createBackground: function(monitorIndex) {
+ let bgManager = new Background.BackgroundManager({ container: this._backgroundGroup,
+ layoutManager: this,
+ monitorIndex: monitorIndex });
+
+ bgManager.connect('changed', Lang.bind(this, function() {
+ BackgroundMenu.addBackgroundMenu(bgManager.background.actor);
+ }));
+
+ this._bgManagers.push(bgManager);
+
+ return bgManager.background;
+ },
+
+ _createSecondaryBackgrounds: function() {
+ for (let i = 0; i < this.monitors.length; i++) {
+ if (i != this.primaryIndex) {
+ let background = this._createBackground(i);
+
+ background.actor.opacity = 0;
+ Tweener.addTween(background.actor,
+ { opacity: 255,
+ time: BACKGROUND_FADE_ANIMATION_TIME,
+ transition: 'easeOutQuad' });
+ }
+ }
+ },
+
+ _createPrimaryBackground: function() {
+ this._createBackground(this.primaryIndex);
+ },
+
+ _updateBackgrounds: function() {
+ let i;
+ for (i = 0; i < this._bgManagers.length; i++)
+ this._bgManagers[i].destroy();
+
+ this._bgManagers = [];
+
+ if (Main.sessionMode.isGreeter)
+ return;
+
+ if (this._startingUp)
+ return;
+
+ for (let i = 0; i < this.monitors.length; i++) {
+ this._createBackground(i);
+ }
+ },
+
_updateBoxes: function() {
this.screenShieldGroup.set_position(0, 0);
this.screenShieldGroup.set_size(global.screen_width, global.screen_height);
this._updateBoxes();
this._updateTrayBarrier();
this._updateHotCorners();
+ this._updateBackgrounds();
this._updateFullscreen();
this._updateVisibility();
this._queueUpdateRegions();
return this._keyboardIndex;
},
- prepareStartupAnimation: function() {
- this.panelBox.translation_y = -this.panelBox.height;
- },
+ // Startup Animations
+ //
+ // We have two different animations, depending on whether we're a greeter
+ // or a normal session.
+ //
+ // In the greeter, we want to animate the panel from the top, and smoothly
+ // fade the login dialog on top of whatever plymouth left on screen which
+ // we get as a still frame background before drawing anything else.
+ //
+ // Here we just have the code to animate the panel, and fade up the background.
+ // The login dialog animation is handled by modalDialog.js
+ //
+ // When starting a normal user session, we want to grow it out of the middle
+ // of the screen.
+ //
+ // Usually, we don't want to paint the stage background color because the
+ // MetaBackgroundActor inside global.window_group covers the entirety of the
+ // screen. So, we set no_clear_hint at the end of the animation.
- startupAnimation: function() {
- let plymouthTransitionRunning = false;
+ _prepareStartupAnimation: function() {
+ // Set ourselves to FULLSCREEN input mode while the animation is running
+ // so events don't get delivered to X11 windows (which are distorted by the animation)
+ global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
- // If we're the greeter, put up the xrootpmap actor
- // and fade it out to have a nice transition from plymouth
- // to the greeter. Otherwise, we'll just animate the panel,
- // as usual.
- if (Main.sessionMode.isGreeter) {
- this._background = Meta.BackgroundActor.new_for_screen(global.screen);
- if (this._background != null) {
- this.uiGroup.add_actor(this._background);
- Tweener.addTween(this._background,
- { opacity: 0,
- time: PLYMOUTH_TRANSITION_TIME,
- transition: 'linear',
- onComplete: this._fadeBackgroundComplete,
- onCompleteScope: this });
- plymouthTransitionRunning = true;
- }
+ // build new backgrounds
+ for (let i = 0; i < this.monitors.length; i++) {
+ let monitor = this.monitors[i];
+
+ let stillFrame = new Background.StillFrame(i);
+ this._consoleBackgroundGroup.add_child(stillFrame.actor);
+
+ stillFrame.actor.set_size(this.monitors[i].width, this.monitors[i].height);
+ stillFrame.actor.set_position(this.monitors[i].x, this.monitors[i].y);
}
- if (!plymouthTransitionRunning)
- this._fadeBackgroundComplete();
+ if (Main.sessionMode.isGreeter) {
+ this.panelBox.translation_y = -this.panelBox.height;
+ } else {
+ let monitor = this.primaryMonitor;
+ let x = monitor.x + monitor.width / 2.0;
+ let y = monitor.y + monitor.height / 2.0;
+
+ this.uiGroup.set_pivot_point(x / global.screen_width,
+ y / global.screen_height);
+ this.uiGroup.scale_x = this.uiGroup.scale_y = 0;
+ }
},
- _fadeBackgroundComplete: function() {
- this._freezeUpdateRegions();
+ startupAnimation: function() {
+ if (Main.sessionMode.isGreeter)
+ this._startupAnimationGreeter();
+ else
+ this._startupAnimationSession();
+ },
- if (this._background != null) {
- this._background.destroy();
- this._background = null;
- }
+ _startupAnimationGreeter: function() {
+ this._freezeUpdateRegions();
+ Tweener.addTween(this.panelBox,
+ { translation_y: 0,
+ time: STARTUP_ANIMATION_TIME,
+ transition: 'easeOutQuad',
+ onComplete: this._startupAnimationComplete,
+ onCompleteScope: this });
+ },
- Tweener.addTween(this.panelBox,
- { translation_y: 0,
+ _startupAnimationSession: function() {
+ this._freezeUpdateRegions();
+ this._createPrimaryBackground();
+ Tweener.addTween(this.uiGroup,
+ { scale_x: 1,
+ scale_y: 1,
time: STARTUP_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._startupAnimationComplete,
- onCompleteScope: this
- });
+ onCompleteScope: this });
},
_startupAnimationComplete: function() {
+ // At this point, the UI group is covering everything, so
+ // we no longer need to clear the stage
+ global.stage.no_clear_hint = true;
+
+ global.stage_input_mode = Shell.StageInputMode.NORMAL;
+
+ this._consoleBackgroundGroup.destroy();
+
+ if (Main.sessionMode.isGreeter)
+ this._createSecondaryBackgrounds();
+
this.emit('panel-box-changed');
this._thawUpdateRegions();
},
const Shell = imports.gi.Shell;
const St = imports.gi.St;
-const BackgroundMenu = imports.ui.backgroundMenu;
const Components = imports.ui.components;
const CtrlAltTab = imports.ui.ctrlAltTab;
const EndSessionDialog = imports.ui.endSessionDialog;
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
componentManager = new Components.ComponentManager();
- BackgroundMenu.addBackgroundMenu(global.background_actor);
-
layoutManager.init();
- layoutManager.prepareStartupAnimation();
overview.init();
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
const Shell = imports.gi.Shell;
const Gdk = imports.gi.Gdk;
+const Background = imports.ui.background;
const Dash = imports.ui.dash;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
// Time for initial animation going into Overview mode
const ANIMATION_TIME = 0.25;
-const DND_WINDOW_SWITCH_TIMEOUT = 1250;
+// Must be less than ANIMATION_TIME, since we switch to
+// or from the overview completely after ANIMATION_TIME,
+// and don't want the shading animation to get cut off
+const SHADE_ANIMATION_TIME = .20;
-const GLSL_DIM_EFFECT_DECLARATIONS = '';
-const GLSL_DIM_EFFECT_CODE = '\
- vec2 dist = cogl_tex_coord_in[0].xy - vec2(0.5, 0.5); \
- float elipse_radius = 0.5; \
- /* from https://bugzilla.gnome.org/show_bug.cgi?id=669798: \
- the alpha on the gradient goes from 250 at its darkest to 180 at its most transparent. */ \
- float y = 250.0 / 255.0; \
- float x = 180.0 / 255.0; \
- /* interpolate darkening value, based on distance from screen center */ \
- float val = min(length(dist), elipse_radius); \
- float a = mix(x, y, val / elipse_radius); \
- /* dim_factor varies from [1.0 -> 0.5] when overview is showing \
- We use it to smooth value, then we clamp it to valid color interval */ \
- a = clamp(a - cogl_color_in.r + 0.5, 0.0, 1.0); \
- /* We\'re blending between: color and black color (obviously omitted in the equation) */ \
- cogl_color_out.xyz = cogl_color_out.xyz * (1.0 - a); \
- cogl_color_out.a = 1.0;';
+const DND_WINDOW_SWITCH_TIMEOUT = 1250;
const ShellInfo = new Lang.Class({
Name: 'ShellInfo',
this._overviewCreated = true;
- // The main BackgroundActor is inside global.window_group which is
+ // The main Background actors are inside global.window_group which are
// hidden when displaying the overview, so we create a new
// one. Instances of this class share a single CoglTexture behind the
// scenes which allows us to show the background with different
// rendering options without duplicating the texture data.
- this._background = Meta.BackgroundActor.new_for_screen(global.screen);
- this._background.add_glsl_snippet(Meta.SnippetHook.FRAGMENT,
- GLSL_DIM_EFFECT_DECLARATIONS,
- GLSL_DIM_EFFECT_CODE,
- false);
- this._background.hide();
- global.overlay_group.add_actor(this._background);
+ let monitor = Main.layoutManager.primaryMonitor;
this._desktopFade = new St.Bin();
global.overlay_group.add_actor(this._desktopFade);
this._group = new St.BoxLayout({ name: 'overview-group',
clip_to_allocation: true });
+ this._backgroundGroup = new Meta.BackgroundGroup();
+ global.overlay_group.add_child(this._backgroundGroup);
+ this._backgroundGroup.hide();
+ this._bgManagers = [];
+
this._capturedEventId = 0;
this._buttonPressId = 0;
this.init();
},
+ _updateBackgrounds: function() {
+ for (let i = 0; i < this._bgManagers.length; i++)
+ this._bgManagers[i].destroy();
+
+ this._bgManagers = [];
+
+ for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
+ let bgManager = new Background.BackgroundManager({ container: this._backgroundGroup,
+ monitorIndex: i,
+ effects: Meta.BackgroundEffects.VIGNETTE });
+ this._bgManagers.push(bgManager);
+ }
+ },
+
+ _unshadeBackgrounds: function() {
+ let backgrounds = this._backgroundGroup.get_children();
+ for (let i = 0; i < backgrounds.length; i++) {
+ let background = backgrounds[i]._delegate;
+
+ Tweener.addTween(background,
+ { brightness: 1.0,
+ time: SHADE_ANIMATION_TIME,
+ transition: 'easeOutQuad'
+ });
+ Tweener.addTween(background,
+ { vignetteSharpness: 0.0,
+ time: SHADE_ANIMATION_TIME,
+ transition: 'easeOutQuad'
+ });
+ }
+ },
+
+ _shadeBackgrounds: function() {
+ let backgrounds = this._backgroundGroup.get_children();
+ for (let i = 0; i < backgrounds.length; i++) {
+ let background = backgrounds[i]._delegate;
+
+ Tweener.addTween(background,
+ { brightness: 0.8,
+ time: SHADE_ANIMATION_TIME,
+ transition: 'easeOutQuad'
+ });
+ Tweener.addTween(background,
+ { vignetteSharpness: 0.7,
+ time: SHADE_ANIMATION_TIME,
+ transition: 'easeOutQuad'
+ });
+ }
+ },
+
_sessionUpdated: function() {
this.isDummy = !Main.sessionMode.hasOverview;
this._createOverview();
this._coverPane.set_position(0, workArea.y);
this._coverPane.set_size(workArea.width, workArea.height);
+
+ this._updateBackgrounds();
},
_onRestacked: function() {
global.window_group.hide();
global.top_window_group.hide();
this._overview.show();
- this._background.show();
+ this._backgroundGroup.show();
this._viewSelector.show();
this._overview.opacity = 0;
onComplete: this._showDone,
onCompleteScope: this
});
-
- Tweener.addTween(this._background,
- { dim_factor: 0.8,
- time: ANIMATION_TIME,
- transition: 'easeOutQuad'
- });
+ this._shadeBackgrounds();
this._coverPane.raise_top();
this._coverPane.show();
onComplete: this._hideDone,
onCompleteScope: this
});
-
- Tweener.addTween(this._background,
- { dim_factor: 1.0,
- time: ANIMATION_TIME,
- transition: 'easeOutQuad'
- });
+ this._unshadeBackgrounds();
this._coverPane.raise_top();
this._coverPane.show();
this._viewSelector.hide();
this._desktopFade.hide();
- this._background.hide();
+ this._backgroundGroup.hide();
this._overview.hide();
this.visible = false;
const St = imports.gi.St;
const TweenerEquations = imports.tweener.equations;
+const Background = imports.ui.background;
const GnomeSession = imports.misc.gnomeSession;
const Hash = imports.misc.hash;
const Layout = imports.ui.layout;
// - STANDARD_FADE_TIME is used when the session goes idle
// - MANUAL_FADE_TIME is used for lowering the shield when asked by the user,
// or when cancelling the dialog
+// - BACKGROUND_FADE_TIME is used when the background changes to crossfade to new background
// - CURTAIN_SLIDE_TIME is used when raising the shield before unlocking
// - INITIAL_FADE_IN_TIME is used for the initial fade in at startup
const STANDARD_FADE_TIME = 10;
const MANUAL_FADE_TIME = 0.8;
+const BACKGROUND_FADE_TIME = 1.0;
const CURTAIN_SLIDE_TIME = 0.3;
const INITIAL_FADE_IN_TIME = 0.25;
-function sample(offx, offy) {
- return 'texel += texture2D (sampler, tex_coord.st + pixel_step * ' +
- 'vec2 (' + offx + ',' + offy + '));\n'
-}
-const GLSL_BLUR_EFFECT_DECLARATIONS = ' \
-uniform vec2 pixel_step;\n \
-uniform float desaturation;\n \
-vec4 apply_blur(in sampler2D sampler, in vec2 tex_coord) {\n \
- vec4 texel;\n \
- texel = texture2D (sampler, tex_coord.st);\n'
- + sample(-1.0, -1.0)
- + sample( 0.0, -1.0)
- + sample(+1.0, -1.0)
- + sample(-1.0, 0.0)
- + sample(+1.0, 0.0)
- + sample(-1.0, +1.0)
- + sample( 0.0, +1.0)
- + sample(+1.0, +1.0) + ' \
- texel /= 9.0;\n \
- return texel;\n \
-}\n \
-vec3 desaturate (const vec3 color)\n \
-{\n \
- const vec3 gray_conv = vec3 (0.299, 0.587, 0.114);\n \
- vec3 gray = vec3 (dot (gray_conv, color));\n \
- return vec3 (mix (color.rgb, gray, desaturation));\n \
-}';
-const GLSL_BLUR_EFFECT_CODE = ' \
-cogl_texel = apply_blur(cogl_sampler, cogl_tex_coord.st);\n \
-cogl_texel.rgb = desaturate(cogl_texel.rgb);\n';
-
-
const Clock = new Lang.Class({
Name: 'ScreenShieldClock',
name: 'lockScreenContents' });
this._lockScreenContents.add_constraint(new Layout.MonitorConstraint({ primary: true }));
- let backgroundActor = Meta.BackgroundActor.new_for_screen(global.screen);
- backgroundActor.add_glsl_snippet(Meta.SnippetHook.TEXTURE_LOOKUP,
- GLSL_BLUR_EFFECT_DECLARATIONS,
- GLSL_BLUR_EFFECT_CODE,
- true);
- backgroundActor.set_uniform_float('desaturation',
- 1, 1, [0.6]);
- backgroundActor.connect('notify::size', function(actor) {
- actor.set_uniform_float('pixel_step', 2, 1, [1/actor.width, 1/actor.height]);
- });
-
- this._background = new St.Bin({ style_class: 'screen-shield-background',
- child: backgroundActor });
- this._lockScreenGroup.add_actor(this._background);
this._lockScreenGroup.add_actor(this._lockScreenContents);
+ this._backgroundGroup = new Meta.BackgroundGroup();
+
+ this._lockScreenGroup.add_actor(this._backgroundGroup);
+ this._backgroundGroup.lower_bottom();
+ this._bgManagers = [];
+
+ this._updateBackgrounds();
+ Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateBackgrounds));
+
this._arrowContainer = new St.BoxLayout({ style_class: 'screen-shield-arrows',
vertical: true,
x_align: Clutter.ActorAlign.CENTER,
this.idleMonitor = new GnomeDesktop.IdleMonitor();
},
+ _createBackground: function(monitorIndex) {
+ let bin = new St.Bin({ style_class: 'screen-shield-background' });
+
+ let bgManager = new Background.BackgroundManager({ container: bin,
+ monitorIndex: monitorIndex,
+ effects: Meta.BackgroundEffects.BLUR | Meta.BackgroundEffects.DESATURATE });
+
+ bgManager.background.saturation = 0.6;
+
+ this._bgManagers.push(bgManager);
+
+ this._backgroundGroup.add_child(bin);
+ bin.lower_bottom();
+ },
+
+ _updateBackgrounds: function() {
+ for (let i = 0; i < this._bgManagers.length; i++)
+ this._bgManagers[i].destroy();
+
+ this._bgManagers = [];
+
+ for (let i = 0; i < Main.layoutManager.monitors.length; i++)
+ this._createBackground(i);
+ },
+
_liftShield: function(onPrimary, velocity) {
if (this._isLocked) {
this._ensureUnlockDialog(onPrimary, true /* allowCancel */);
const Signals = imports.signals;
const St = imports.gi.St;
+const Background = imports.ui.background;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
- this._background = Meta.BackgroundActor.new_for_screen(global.screen);
- this._contents.add_actor(this._background);
+ this._createBackground();
let monitor = Main.layoutManager.primaryMonitor;
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
this._collapseFraction = 0; // Not collapsed
},
+ _createBackground: function() {
+ this._bgManager = new Background.BackgroundManager({ monitorIndex: Main.layoutManager.primaryIndex,
+ container: this._contents,
+ effects: Meta.BackgroundEffects.NONE });
+ },
+
setPorthole: function(x, y, width, height) {
this._portholeX = x;
this._portholeY = y;
let clone = this._windows[i];
let metaWindow = clone.metaWindow;
if (i == 0) {
- clone.setStackAbove(this._background);
+ clone.setStackAbove(this._bgManager.background.actor);
} else {
let previousClone = this._windows[i - 1];
clone.setStackAbove(previousClone.actor);
destroy : function() {
this.actor.destroy();
+ this._bgManager.destroy();
+ this._bgManager = null;
},
workspaceRemoved : function() {
this._contents.add_actor(clone.actor);
if (this._windows.length == 0)
- clone.setStackAbove(this._background);
+ clone.setStackAbove(this._bgManager.actor);
else
clone.setStackAbove(this._windows[this._windows.length - 1].actor);
PROP_STAGE_INPUT_MODE,
PROP_WINDOW_GROUP,
PROP_TOP_WINDOW_GROUP,
- PROP_BACKGROUND_ACTOR,
PROP_WINDOW_MANAGER,
PROP_SETTINGS,
PROP_DATADIR,
case PROP_TOP_WINDOW_GROUP:
g_value_set_object (value, meta_get_top_window_group_for_screen (global->meta_screen));
break;
- case PROP_BACKGROUND_ACTOR:
- g_value_set_object (value, meta_get_background_actor_for_screen (global->meta_screen));
- break;
case PROP_WINDOW_MANAGER:
g_value_set_object (value, global->wm);
break;
CLUTTER_TYPE_ACTOR,
G_PARAM_READABLE));
- g_object_class_install_property (gobject_class,
- PROP_BACKGROUND_ACTOR,
- g_param_spec_object ("background-actor",
- "Background Actor",
- "Actor drawing root window background",
- CLUTTER_TYPE_ACTOR,
- G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_WINDOW_MANAGER,
g_param_spec_object ("window-manager",